package com.iflytek.ossp.auth.service;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.iflytek.ossp.auth.entity.MenuInfo;
import com.iflytek.ossp.dao.JpaDao;
import com.iflytek.ossp.shiro.ShiroUser;

@Service("menuService")
public class MenuService {

	@Resource
	private JpaDao authDao;

	public MenuInfo getMenuById(Long id) {
		if (id == null) {
			return null;
		}
		return authDao.find(MenuInfo.class, id);
	}

	public List<MenuInfo> getMenusByParent(Long parentId) {
		if (parentId == null) {
			return authDao
					.find("from MenuInfo where parent.id is null order by menuOrder");
		}
		return authDao.find(
				"from MenuInfo where parent.id=? order by menuOrder", parentId);
	}

	public List<MenuInfo> getMenusByRole(Long roleId) {
		String hql = "select distinct rmi.menu from RoleMenuInfo rmi where rmi.role.id = ?";
		return authDao.find(hql, roleId);
	}
	
	public List<MenuInfo> getMenusByUser(Long userId) {
		return authDao.find("select distinct rmi.menu from RoleUserInfo rui,RoleMenuInfo rmi" +
				" where rui.role.id=rmi.role.id and rui.user.id=?", userId);
	}

	public List<MenuInfo> getPermitMenusByParent(Long parentId) {
		ShiroUser su = UserService.getCurrentShiroUser();
		if (su == null) {
			return new ArrayList<MenuInfo>();
		}
		if("admin".equals(su.getLoginName())) {
			return getMenusByParent(parentId);
		}
		List<Object> params = new ArrayList<Object>();
		String hql = "select distinct rmi.menu from RoleMenuInfo rmi,RoleUserInfo rui"
				+ " where rmi.role = rui.role and rui.user.id = ?";
		params.add(su.getId());
		if (parentId == null) {
			hql += " and rmi.menu.parent is null";
		} else {
			hql += " and rmi.menu.parent.id = ?";
			params.add(parentId);
		}
		return authDao.find(hql, params.toArray());

	}

	public List<MenuInfo> getMenusByParentAndRole(Long parentId, Long roleId) {
		if (roleId == null) {
			return new ArrayList<MenuInfo>();
		}
		List<Object> params = new ArrayList<Object>();
		String hql = "select distinct rmi.menu from RoleMenuInfo rmi where rmi.role.id=?";
		params.add(roleId);
		if (parentId == null) {
			hql += " and rmi.menu.parent is null";
		} else {
			hql += " and rmi.menu.parent.id = ?";
			params.add(parentId);
		}
		return authDao.find(hql, params.toArray());
	}

	public void saveMenu(MenuInfo menu) {
		authDao.save(menu);
	}

	@Transactional
	public void deleteMenu(Long id) {
		MenuInfo menu = getMenuById(id);
		if (menu == null) {
			return;
		}
		clearSubMenus(id);
		if (menu.getParent() != null) {
			authDao.bulkUpdate(
					"update MenuInfo set menuOrder = menuOrder -1 where parent.id=? and menuOrder>?",
					menu.getParent().getId(), menu.getMenuOrder());
		} else {
			authDao.bulkUpdate(
					"update MenuInfo set menuOrder = menuOrder -1 where parent is null and menuOrder>?",
					menu.getMenuOrder());
		}
		authDao.bulkUpdate("delete from RoleMenuInfo where menu.id=?", id);
		authDao.bulkUpdate("delete from MenuInfo where id=?", id);

	}

	@Transactional
	public void clearSubMenus(Long id) {
		List<MenuInfo> subMenus = getMenusByParent(id);
		for (MenuInfo sub : subMenus) {
			clearSubMenus(sub.getId());
			authDao.bulkUpdate("delete from RoleMenuInfo where menu.id=?",
					sub.getId());
			authDao.bulkUpdate("delete from MenuInfo where id=?", sub.getId());
		}
	}

	@Transactional
	public void clearRole(Long id) {
		List<MenuInfo> subMenus = getMenusByParent(id);
		for (MenuInfo sub : subMenus) {
			clearRole(sub.getId());
		}
		authDao.bulkUpdate("delete from RoleMenuInfo where menu.id=?", id);
	}

	@Transactional
	public void moveMenu(Long id, Long toId, Integer order) {
		if (id == null || order == null) {
			return;
		}
		MenuInfo menu = getMenuById(id);
		MenuInfo to = getMenuById(toId);
		MenuInfo from = menu.getParent();

		if (to == null) {
			if (from == null) {
				smallMove(menu, order);
			} else {
				bigMove(from, to, menu, order);
			}
		} else {
			if (to.equals(from)) {
				smallMove(menu, order);
			} else {
				bigMove(from, to, menu, order);
			}
		}

	}

	@Transactional
	public void smallMove(MenuInfo menu, Integer order) {
		if (menu == null) {
			return;
		}
		MenuInfo _menu = getMenuByOrder(menu.getParent(), order);
		Integer _order = menu.getMenuOrder();
		menu.setMenuOrder(order);
		_menu.setMenuOrder(_order);
		saveMenu(_menu);
		saveMenu(menu);
	}

	@Transactional
	public void bigMove(MenuInfo from, MenuInfo to, MenuInfo menu, Integer order) {
		clearRole(menu.getId());
		Integer _order = menu.getMenuOrder();
		menu.setParent(to);
		menu.setMenuOrder(order);
		saveMenu(menu);

		if (from != null) {
			authDao.bulkUpdate(
					"update MenuInfo set menuOrder = menuOrder - 1 where parent.id = ? and menuOrder > ?",
					from.getId(), _order);
		} else {
			authDao.bulkUpdate(
					"update MenuInfo set menuOrder = menuOrder - 1 where parent is null and menuOrder > ?",
					_order);
		}

		if (to != null) {
			authDao.bulkUpdate(
					"update MenuInfo set menuOrder = menuOrder + 1 where parent.id = ? and menuOrder >= ? and id !=?",
					to.getId(), order, menu.getId());
		} else {
			authDao.bulkUpdate(
					"update MenuInfo set menuOrder = menuOrder + 1 where parent is null and menuOrder >= ? and id !=?",
					order, menu.getId());
		}
	}

	public MenuInfo getMenuByOrder(MenuInfo parent, Integer order) {
		if (parent == null) {
			List<MenuInfo> list = authDao.find(
					"from MenuInfo where parent is null and menuOrder = ?",
					order);
			if (list.size() > 0) {
				return list.get(0);
			}
		} else {
			List<MenuInfo> list = authDao.find(
					"from MenuInfo where parent.id = ? and menuOrder = ?",
					parent.getId(), order);
			if (list.size() > 0) {
				return list.get(0);
			}
		}
		return null;
	}
}
